package com.xbongbong.paas.service.recheck;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.domain.entity.PaasProcessDataEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.elasticsearch.model.PaasFormDataEsModel;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.field.CustomRecheckRulePojo;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.field.SubFormPoJo;
import com.xbongbong.paas.help.CommonHelp;
import com.xbongbong.sys.help.PackageHelp;
import com.xbongbong.paas.help.RecheckingAddRuleHelp;
import com.xbongbong.paas.model.PaasProcessDataModel;
import com.xbongbong.paas.pojo.dto.FormDataRepeatDTO;
import com.xbongbong.paas.pojo.vo.CheckRepeatVO;
import com.xbongbong.paas.pojo.vo.FormDataRepeatVO;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.pro.common.pojo.RepeatSearchFieldPojo;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.enums.PackageTypeEnum;
import com.xbongbong.pro.enums.errorcodes.ProErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.recheck.pojo.RecheckAttrRulePojo;
import com.xbongbong.pro.recheck.pojo.RecheckFormRulePojo;
import com.xbongbong.pro.recheck.pojo.dto.RecheckAddEditDTO;
import com.xbongbong.pro.user.pojo.ReturnUserAndDepartmentPojo;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.RecheckingRuleEntity;
import com.xbongbong.saas.enums.RecheckMatchWayEnum;
import com.xbongbong.saas.model.PaasFormSubDataModel;
import com.xbongbong.saas.model.RecheckingRuleModel;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.join.query.HasChildQueryBuilder;
import org.elasticsearch.join.query.JoinQueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.TreeSet;
import java.util.stream.Collectors;

import static com.xbongbong.paas.elasticsearch.constant.EsNormalConstant.MINI_MUM_SHOULD_MATCH;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchPhraseQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;
/**
 * @description 新建编辑页判重抽象类
 * @author yanglei
 * @date 2022/11/22 8:59
 */
@Component
public abstract class AbstractRecheckAddEditStrategy implements RecheckingAddEditService {

    private static final Logger LOG = LoggerFactory.getLogger(AbstractRecheckAddEditStrategy.class);

    @Resource
    private CommonHelp commonHelp;
    @Resource
    private RecheckingAddRuleHelp recheckingAddRuleHelp;
    @Resource
    private PaasFormDataEsModel paasFormDataEsModel;
    @Resource
    private RecheckingRuleModel recheckingRuleModel;
    @Resource
    private PackageHelp packageHelp;
    @Resource
    private PaasProcessDataModel paasProcessDataModel;
    @Resource
    private PaasFormSubDataModel paasFormSubDataModel;


    public CheckRepeatVO abstractExecuteRule(FormDataRepeatDTO formDataRepeatDTO) throws XbbException{
        CheckRepeatVO checkRepeatVO = new CheckRepeatVO();
        BoolQueryBuilder checkToolBoolQuery = boolQuery();
        BoolQueryBuilder noRepeatBoolQuery = boolQuery();
        RecheckAddEditDTO recheckAddEditDTO = new RecheckAddEditDTO();
        //设置顶级公共传参
        setCommonRecheckAddEditDTO(formDataRepeatDTO,recheckAddEditDTO,checkRepeatVO);
        //设置顶级各自特殊传参
        setSpecialRecheckAddEditDTO(formDataRepeatDTO,recheckAddEditDTO,checkRepeatVO);
        //设置公共条件
        setCommonCondition(recheckAddEditDTO,checkToolBoolQuery,noRepeatBoolQuery);
        //处理系统字段查重查询条件
        handleSystemAttrQueryBuilder(recheckAddEditDTO,checkToolBoolQuery,noRepeatBoolQuery);
        //处理自定义字段查询条件
        handleCustomAttrQueryBuilder(recheckAddEditDTO,checkToolBoolQuery,noRepeatBoolQuery);
        //如果新建不允许重复查出来的数据为空,再去用查重工具规则查
        List<PaasFormDataEntityExt> noRepeatDataList = queryResult(recheckAddEditDTO, noRepeatBoolQuery);
        //导入不需要校验查重工具规则
        if (!recheckAddEditDTO.getIsImport() && recheckAddEditDTO.getIsRecheckPermission() && recheckAddEditDTO.getIsEdit()){
            List<PaasFormDataEntityExt> checkToolDataList = queryResult(recheckAddEditDTO, checkToolBoolQuery);
            recheckAddEditDTO.getCheckToolDataMap().put(businessType(),checkToolDataList);
        }
        recheckAddEditDTO.getNoRepeatDataMap().put(businessType(),noRepeatDataList);
        //名称字段在审批中的处理
        handleNameInApproval(recheckAddEditDTO);
        return resultDeal(recheckAddEditDTO);
    }

    /**
     * @description 公共的传参封装
     * @author yanglei
     * @date 2022/11/22 15:52
     * @param formDataRepeatDTO
     * @param recheckAddEditDTO
     * @param checkRepeatVO
     */
    protected void setCommonRecheckAddEditDTO(FormDataRepeatDTO formDataRepeatDTO, RecheckAddEditDTO recheckAddEditDTO, CheckRepeatVO checkRepeatVO) throws XbbException{
        String corpid = formDataRepeatDTO.getCorpid();
        Integer businessType = formDataRepeatDTO.getBusinessType();
        Long formId = formDataRepeatDTO.getFormId();
        //获取当前模板的重复规则
        RecheckingRuleEntity ruleEntity = recheckingRuleModel.getRuleListByFormId(corpid,formId, businessType);
        if (Objects.isNull(ruleEntity)){
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        recheckAddEditDTO.setDataId(formDataRepeatDTO.getDataId());
        recheckAddEditDTO.setFormId(formId);
        recheckAddEditDTO.setCorpid(formDataRepeatDTO.getCorpid());
        recheckAddEditDTO.setBusinessType(formDataRepeatDTO.getBusinessType());
        recheckAddEditDTO.setAllFormIdList(recheckingAddRuleHelp.getAllFormIdList(corpid, businessType));
        recheckAddEditDTO.setExplainMap(recheckingAddRuleHelp.getExplainMap(formId,corpid));
        recheckAddEditDTO.setFeeType(packageHelp.getFeeType(corpid));
        recheckAddEditDTO.setAttr(formDataRepeatDTO.getAttr());
        recheckAddEditDTO.setSubAttr(formDataRepeatDTO.getSubAttr());
        recheckAddEditDTO.setValue(formDataRepeatDTO.getValue());
        recheckAddEditDTO.setSubValueList(formDataRepeatDTO.getSubValueList());
        recheckAddEditDTO.setRuleEntity(ruleEntity);
        recheckAddEditDTO.setCheckRepeatVO(checkRepeatVO);
        recheckAddEditDTO.setIsEdit(formDataRepeatDTO.getIsEdit() != null);
        recheckAddEditDTO.setCheckToolDataMap(new HashMap<>(1 << 4));
        recheckAddEditDTO.setNoRepeatDataMap(new HashMap<>(1 << 4));
        recheckAddEditDTO.setTaskId(formDataRepeatDTO.getTaskId());
        recheckAddEditDTO.setIsImport(formDataRepeatDTO.getIsImport() != null);
        recheckAddEditDTO.setIsOpenWorkflow(commonHelp.isOpenWorkFlow(corpid));
    }

    /**
     * @description 公共条件封装
     * @author yanglei
     * @date 2023/1/3 9:11
     * @param recheckAddEditDTO
     * @param checkToolBoolQuery 查重工具查询条件
     * @param noRepeatBoolQuery 新建不允许重复查询条件
     */
    protected void setCommonCondition(RecheckAddEditDTO recheckAddEditDTO, BoolQueryBuilder checkToolBoolQuery,BoolQueryBuilder noRepeatBoolQuery){
        //移除formId
        if (recheckAddEditDTO.getIsOpenWorkflow()) {
            // 如果开启了工作流，审批中数据会进入主表，查重的时候可以直接从主表查到
            checkToolBoolQuery.filter(termsQuery(FieldTypeEnum.FLOW_STATUS.getAlias(), Arrays.asList(FlowStatusEnum.NOT_NEED_APPROVAL.getType(), FlowStatusEnum.PASS.getType(), FlowStatusEnum.APPROVAL_PENDING.getType(), FlowStatusEnum.IN_APPROVAL.getType())));
            noRepeatBoolQuery.filter(termsQuery(FieldTypeEnum.FLOW_STATUS.getAlias(), Arrays.asList(FlowStatusEnum.NOT_NEED_APPROVAL.getType(), FlowStatusEnum.PASS.getType(), FlowStatusEnum.APPROVAL_PENDING.getType(), FlowStatusEnum.IN_APPROVAL.getType())));
        } else {
            checkToolBoolQuery.filter(termsQuery(FieldTypeEnum.FLOW_STATUS.getAlias(), Arrays.asList(FlowStatusEnum.NOT_NEED_APPROVAL.getType(), FlowStatusEnum.PASS.getType())));
            noRepeatBoolQuery.filter(termsQuery(FieldTypeEnum.FLOW_STATUS.getAlias(), Arrays.asList(FlowStatusEnum.NOT_NEED_APPROVAL.getType(), FlowStatusEnum.PASS.getType())));
        }
        checkToolBoolQuery.filter(termsQuery(ParameterConstant.DEL, Arrays.asList(DelEnum.NORMAL.getDel(),DelEnum.DELETE.getDel(),DelEnum.APPROVE_STATUS.getDel())));
        noRepeatBoolQuery.filter(termsQuery(ParameterConstant.DEL, Arrays.asList(DelEnum.NORMAL.getDel(),DelEnum.DELETE.getDel(),DelEnum.APPROVE_STATUS.getDel())));
        checkToolBoolQuery.filter(termQuery(StringConstant.CORPID + ".keyword",recheckAddEditDTO.getCorpid()));
        noRepeatBoolQuery.filter(termQuery(StringConstant.CORPID + ".keyword",recheckAddEditDTO.getCorpid()));
    }

    /**
     * @description 通用结果查询，如果有特殊处理请在各自业务策略维继承实现
     * @author yanglei
     * @date 2022/11/22 14:32
     * @param recheckAddEditDTO
     * @param boolQueryBuilder
     * @return List<PaasFormDataEntityExt>
     */
    @Override
    public List<PaasFormDataEntityExt> queryResult(RecheckAddEditDTO recheckAddEditDTO,BoolQueryBuilder boolQueryBuilder) throws XbbException{
        List<PaasFormDataEntityExt> formDataList;
        try{
            IndexTypeEnum indexTypeEnum = recheckAddEditDTO.getIndexTypeEnum();
            boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD,indexTypeEnum.getType()));
            boolQueryBuilder.minimumShouldMatch(MINI_MUM_SHOULD_MATCH);
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
            Integer pageSize = 10;
            PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 0, pageSize);
            sourceBuilder.query(boolQueryBuilder);
            SearchRequest searchRequest = new SearchRequest(indexTypeEnum.getIndex());
            searchRequest.source(sourceBuilder);
            FormDataRepeatVO formDataRepeatVO = paasFormDataEsModel.repeat(pageRequest, searchRequest);
            formDataList = formDataRepeatVO.getFormDataList();
            //paasFormSubDataModel.findSubEntity(recheckAddEditDTO.getCorpid(), formDataList, recheckAddEditDTO.getSubIndexTypeEnum());
        }catch (XbbException e){
            LOG.error("查重结果查询失败",e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
        return formDataList;
    }

    /**
     * @description 通用结果封装，如果有特殊处理请在各自业务的策略实现
     * @author yanglei
     * @date 2022/11/22 14:32
     * @param recheckAddEditDTO
     * @return CheckRepeatVO
     */
    @Override
    public CheckRepeatVO resultDeal(RecheckAddEditDTO recheckAddEditDTO) throws XbbException{
        CheckRepeatVO checkRepeatVO = recheckAddEditDTO.getCheckRepeatVO();
        Map<Integer, List<PaasFormDataEntityExt>> checkToolDataMap = recheckAddEditDTO.getCheckToolDataMap();
        Map<Integer, List<PaasFormDataEntityExt>> noRepeatDataMap = recheckAddEditDTO.getNoRepeatDataMap();
        //当前业务本身出来的重复数据
        List<PaasFormDataEntityExt> checkToolDataList = checkToolDataMap.getOrDefault(businessType(), new ArrayList<>());
        List<PaasFormDataEntityExt> noRepeatDataList = noRepeatDataMap.getOrDefault(businessType(), new ArrayList<>());
        //是编辑触发接口，将dataId相同的数据移除
        Long dataId = recheckAddEditDTO.getDataId();
        if (Objects.nonNull(dataId)){
            if (CollectionsUtil.isNotEmpty(checkToolDataList)){
                checkToolDataList.removeIf(item -> Objects.nonNull(item.getId()) && Objects.equals(dataId, item.getId()));
            }
            if (CollectionsUtil.isNotEmpty(noRepeatDataList)) {
                noRepeatDataList.removeIf(item -> Objects.nonNull(item.getId()) && Objects.equals(dataId, item.getId()));

            }
        }
        setCheckType(checkRepeatVO,noRepeatDataList,checkToolDataList);
        setManyRepeat(recheckAddEditDTO,checkRepeatVO,noRepeatDataList,checkToolDataList);
        return checkRepeatVO;
    }


    /**
     * @description 设置存在重复值和 “可能存在重复值的逻辑”
     * @author yanglei
     * @date 2023/1/3 11:12
     * @param checkRepeatVO 返回值
     * @param noRepeatDataList 新建不允许重复查出来的重复数据
     * @param checkToolDataList 查重工具规则查询出来的重复数据
     */
    protected void setCheckType(CheckRepeatVO checkRepeatVO,List<PaasFormDataEntityExt> noRepeatDataList,List<PaasFormDataEntityExt> checkToolDataList){
        if (CollectionsUtil.isEmpty(checkToolDataList) && CollectionsUtil.isEmpty(noRepeatDataList)){
            checkRepeatVO.setNoRepeat(true);
        }else if(CollectionsUtil.isNotEmpty(noRepeatDataList) && CollectionsUtil.isNotEmpty(checkToolDataList)){
            //都不为空，证明有查重工具权限，能点击穿透，并且存在重复值
            checkRepeatVO.setNoRepeat(false);
            checkRepeatVO.setCheckType(BasicConstant.ONE);
            checkRepeatVO.setMessage(ProErrorCodeEnum.API_ERROR_260060.getMsg());
        }else if(CollectionsUtil.isNotEmpty(noRepeatDataList) && CollectionsUtil.isEmpty(checkToolDataList)) {
            //新建的不为空，查重工具规则为空，证明存在重复值，没有查重工具权限，不能点击穿透
            checkRepeatVO.setNoRepeat(false);
            checkRepeatVO.setCheckType(BasicConstant.ZERO);
            checkRepeatVO.setMessage(ProErrorCodeEnum.API_ERROR_260060.getMsg());
        }else if(CollectionsUtil.isEmpty(noRepeatDataList) && CollectionsUtil.isNotEmpty(checkToolDataList)){
            //新建为空，查重工具规则不为空，证明 ” 可能 “存在重复值，有查重工具权限，能点击穿透
            checkRepeatVO.setNoRepeat(false);
            checkRepeatVO.setCheckType(BasicConstant.TWO);
            checkRepeatVO.setMessage(ProErrorCodeEnum.API_ERROR_260059.getMsg());
        }
    }

    /**
     * @description 本身业务自审批中设置多条重复逻辑
     * @author yanglei
     * @date 2023/1/3 11:13
     * @param recheckAddEditDTO 上下文传参
     * @param checkRepeatVO 返回值
     * @param noRepeatDataList 新建不允许重复查出来的重复数据
     * @param checkToolDataList 查重工具规则查询出来的重复数据
     */
    protected void setManyRepeat(RecheckAddEditDTO recheckAddEditDTO,CheckRepeatVO checkRepeatVO,List<PaasFormDataEntityExt> noRepeatDataList,List<PaasFormDataEntityExt> checkToolDataList){
        //获取总的，然后根据id去重
        noRepeatDataList.addAll(checkToolDataList);
        List<PaasFormDataEntityExt> distinctList = noRepeatDataList.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(PaasFormDataEntityExt::getDataId))), ArrayList::new));
        //在es中查出来的数据formDataList.get(0).getId() 不会为空，审批中的为空
        if ( distinctList.size() == 1 && Objects.equals(distinctList.get(0).getId(), recheckAddEditDTO.getDataId()) ) {
            checkRepeatVO.setNoRepeat(true);
            checkRepeatVO.setMessage(null);
        }
        if ( distinctList.size() > 1 ) {
            checkRepeatVO.setManyRepeat(true);
        }
        if (recheckAddEditDTO.getIsImport()){
            checkRepeatVO.setFormDataList(noRepeatDataList);
        }
    }

    /**
     * @description 编号字段的特出查重
     * @author yanglei
     * @date 2022/12/5 18:58
     * @param boolQueryBuilder  查询条件
     * @param value 编号值
     * @param formIdList formIdList
     */
    private void serialNoCheckRepeat(BoolQueryBuilder boolQueryBuilder,Object value,List<Long> formIdList){
        String serialNoAttr = FieldTypeEnum.SERIALNO.getAlias() + StringConstant.POINT + StringConstant.KEY_WORD;
        BoolQueryBuilder queryBuilder = boolQuery();
        boolQueryBuilder.should(queryBuilder.must(termsQuery("formId", formIdList)).must(termQuery(serialNoAttr, value)));
    }

    /**
     * @description 名称字段需要查询审批中的,
     * @author yanglei
     * @date 2022/11/23 14:38
     * @param recheckAddEditDTO
     * @return List<PaasFormDataEntityExt>
     */
    protected void handleNameInApproval(RecheckAddEditDTO recheckAddEditDTO) throws XbbException {
        String attr = recheckAddEditDTO.getAttr();
        Integer businessType = recheckAddEditDTO.getBusinessType();
        Map<Integer, List<PaasFormDataEntityExt>> totalDataMap = recheckAddEditDTO.getNoRepeatDataMap();
        List<PaasFormDataEntityExt> currentDataList = totalDataMap.getOrDefault(businessType, new ArrayList<>());
        boolean nameFlag = StringUtil.isEmpty(recheckAddEditDTO.getSubAttr()) && Objects.equals(recheckAddEditDTO.getNameAttr(), attr) && !recheckAddEditDTO.getIsOpenWorkflow() && Objects.isNull(recheckAddEditDTO.getIsImport());
        RecheckingRuleEntity ruleEntity = recheckAddEditDTO.getRuleEntity();
        //新建不允许重复规则
        List<RecheckFormRulePojo> noRepeatRule = JSONArray.parseArray(ruleEntity.getNoRepeatRule(), RecheckFormRulePojo.class);
        //查重工具规则
        List<RecheckFormRulePojo> checkToolRule = JSONArray.parseArray(ruleEntity.getCheckToolRule(), RecheckFormRulePojo.class);
        //保存动作走新建不允许重复逻辑
        List<PaasProcessDataEntity> paasProcessDataEntityList = handleApprovalNameRecheckRule(recheckAddEditDTO,noRepeatRule,nameFlag);
        if (recheckAddEditDTO.getIsEdit() && recheckAddEditDTO.getIsRecheckPermission()){
            //鼠标失去焦点走查重逻辑
            paasProcessDataEntityList = handleApprovalNameRecheckRule(recheckAddEditDTO,checkToolRule,nameFlag);
        }
        if (CollectionsUtil.isNotEmpty(paasProcessDataEntityList)){
            Iterator<PaasProcessDataEntity> iterator = paasProcessDataEntityList.iterator();
            while(iterator.hasNext()){
                PaasProcessDataEntity paasProcessDataEntity = iterator.next();
                boolean approvalFlag = Objects.equals(paasProcessDataEntity.getFormDataId(),recheckAddEditDTO.getDataId()) && Objects.equals(recheckAddEditDTO.getTaskId(), paasProcessDataEntity.getTaskId());
                if (approvalFlag){
                    iterator.remove();
                }else {
                    PaasFormDataEntityExt paasFormDataEntityExt = new PaasFormDataEntityExt();
                    paasFormDataEntityExt.setData(JSONObject.parseObject(paasProcessDataEntity.getData()));
                    currentDataList.add(paasFormDataEntityExt);
                }
            }
            recheckAddEditDTO.getCheckRepeatVO().setApprovalRepeat(true);
        }
        totalDataMap.put(businessType,currentDataList);
    }

    /**
     * @description 封装精确匹配还是模糊匹配查询条件
     *
     * @author yanglei
     * @date 2022/11/16 20:35
     * @param attr 需要查询的字段attr
     * @param value 需要查询的字段值value
     * @param boolQueryBuilder 查询条件
     * @param formIdList 全局判重 当前业务所有formId
     * @param matchhWay 匹配方式
     */
    protected void packageMatchBoolQueryBuilder(String attr, List<String> value, BoolQueryBuilder boolQueryBuilder, List<Long> formIdList, Integer matchhWay){
        //全局判重和单模板查重仅仅一个formIdList多少的问题
        switch (RecheckMatchWayEnum.getByCode(matchhWay)) {
            case FUZZY_MATCH:
                BoolQueryBuilder fQqueryBuilder = boolQuery();
                boolQueryBuilder.should(fQqueryBuilder.must(termsQuery("formId", formIdList)).must(matchPhraseQuery("data." + attr, value.get(0))));
                break;
            case EXACT_MATCH:
                BoolQueryBuilder eQueryBuilder = boolQuery();
                boolQueryBuilder.should(eQueryBuilder.must(termsQuery("formId", formIdList)).must(termsQuery("data." + attr + ".keyword", value)));
                break;
            default:
                break;
        }
    }

    /**
     * @description 处理新建不允许重复规则
     * @author yanglei
     * @date 2022/11/17 9:34
     * @param rule 规则
     * @param recheckAddEditDTO
     * @param boolQueryBuilder
     */
    protected void handleSystemRecheckingRule(List<RecheckFormRulePojo> rule, RecheckAddEditDTO recheckAddEditDTO, BoolQueryBuilder boolQueryBuilder) throws XbbException {
        Integer businessType = recheckAddEditDTO.getBusinessType();
        String attr = recheckAddEditDTO.getAttr();
        String subAttr = recheckAddEditDTO.getSubAttr();
        String value = recheckAddEditDTO.getValue().toString();
        List<String> subValueList = recheckAddEditDTO.getSubValueList();
        String finalAttr = StringUtil.isNotEmpty(subAttr) ? attr + "."+ recheckAddEditDTO.getSubAttr() : attr;
        Map<String, FieldAttrEntity> explainMap = recheckAddEditDTO.getExplainMap();
        FieldAttrEntity fieldAttrEntity = explainMap.get(attr);
        if (Objects.isNull(fieldAttrEntity)){
            return;
        }
        if (!Objects.equals(fieldAttrEntity.getIsRedundant(),BasicConstant.ZERO)){
            return;
        }
        for (RecheckFormRulePojo formRulePojo : rule) {
            RecheckAttrRulePojo attrRulePojo = recheckingAddRuleHelp.getRecheckAttrRuleByBusinessType(businessType,formRulePojo);
            if (Objects.isNull(attrRulePojo)){
                continue;
            }
            //规则中的字段attr
            String ruleAttr = attrRulePojo.getAttr();
            //当前字段开启了新建不允许重复在规则
            List<Long> formIdList = new ArrayList<>();
            if(Objects.equals(finalAttr,ruleAttr)){
                //全局判重还是仅模板内
                Integer isAll = attrRulePojo.getIsAll();
                formIdList = Arrays.asList(recheckAddEditDTO.getFormId());
                if (Objects.equals(isAll,BasicConstant.ONE)){
                    formIdList = recheckAddEditDTO.getAllFormIdList();
                }
                //精确匹配还是模糊匹配
                Integer matchWay = attrRulePojo.getMatchWay();
                if ( recheckAddEditDTO.getValue() instanceof ReturnUserAndDepartmentPojo) {
                    // 校验员工单选
                    ReturnUserAndDepartmentPojo returnUserAndDepartmentPojo = (ReturnUserAndDepartmentPojo) recheckAddEditDTO.getValue();
                    BoolQueryBuilder queryBuilder = boolQuery();
                    boolQueryBuilder.should(queryBuilder.must(termQuery("formId", recheckAddEditDTO.getFormId())).must(termQuery("data." + attr + ".keyword", returnUserAndDepartmentPojo.getId())));
                }else if(Objects.equals(finalAttr,FieldTypeEnum.SERIALNO.getAlias())){
                    //流水号特殊处理
                    serialNoCheckRepeat(boolQueryBuilder,recheckAddEditDTO.getValue(),formIdList);
                }else {
                    if (CollectionsUtil.isNotEmpty(subValueList)){
                        //这里针对于电话子表单，子表单可以有多个值
                        packageMatchBoolQueryBuilder(finalAttr,subValueList,boolQueryBuilder,formIdList,matchWay);
                    }else {
                        packageMatchBoolQueryBuilder(finalAttr,Arrays.asList(value),boolQueryBuilder,formIdList,matchWay);
                    }
                }
                break;
            }
        }
    }


    /**
     * @description 处理自定义单行文本字段全局判重和模板内判重
     * @author yanglei
     * @date 2022/11/23 17:02
     * @param recheckAddEditDTO
     * @param checkToolBoolQuery
     * @param noRepeatBoolQuery
     */
    public void handleCustomAttrQueryBuilder(RecheckAddEditDTO recheckAddEditDTO, BoolQueryBuilder checkToolBoolQuery,BoolQueryBuilder noRepeatBoolQuery) throws XbbException {
        Integer businessType = recheckAddEditDTO.getBusinessType();
        //是否有查重工具规则权限
        Boolean isRecheckPermission = recheckAddEditDTO.getIsRecheckPermission();
        String attr = recheckAddEditDTO.getAttr();
        Map<String, FieldAttrEntity> explainMap = recheckAddEditDTO.getExplainMap();
        FieldAttrEntity fieldAttrEntity = explainMap.get(attr);
        RecheckingRuleEntity ruleEntity = recheckAddEditDTO.getRuleEntity();
        //新建不允许重复规则
        List<RecheckFormRulePojo> noRepeatRule = JSONArray.parseArray(ruleEntity.getNoRepeatRule(), RecheckFormRulePojo.class);
        handleCustomRecheckingRule(noRepeatBoolQuery,noRepeatRule,businessType,fieldAttrEntity,recheckAddEditDTO);
        //有查重工具权限并且是编辑鼠标失去焦点的入口才封装查重工具规则
        if(isRecheckPermission && recheckAddEditDTO.getIsEdit()){
            //查重工具规则
            List<RecheckFormRulePojo> checkToolRule = JSONArray.parseArray(ruleEntity.getCheckToolRule(), RecheckFormRulePojo.class);
            if (CollectionsUtil.isNotEmpty(checkToolRule)){
                handleCustomRecheckingRule(checkToolBoolQuery,checkToolRule,businessType,fieldAttrEntity,recheckAddEditDTO);
            }
        }
    }
    /**
     * @description 自定义字段 命中重复规则，并且封装查询条件
     * @author yanglei
     * @date 2022/11/17 20:28
     * @param boolQueryBuilder
     * @param ruleList 新建不允许重复规则，或者查重规则
     * @param businessType 业务类型
     * @param fieldAttrEntity 当前字段
     * @param recheckAddEditDTO 顶级传参
     */
    public void handleCustomRecheckingRule(BoolQueryBuilder boolQueryBuilder,List<RecheckFormRulePojo> ruleList,Integer businessType,FieldAttrEntity fieldAttrEntity,RecheckAddEditDTO recheckAddEditDTO) throws XbbException {
        String attr = recheckAddEditDTO.getAttr();
        String subAttr = recheckAddEditDTO.getSubAttr();
        Long formId = recheckAddEditDTO.getFormId();
        for (RecheckFormRulePojo formRulePojo : ruleList){
            RecheckAttrRulePojo clueRule = recheckingAddRuleHelp.getRecheckAttrRuleByBusinessType(businessType, formRulePojo);
            if(Objects.nonNull(clueRule) && Objects.nonNull(fieldAttrEntity)){
                Integer isAll = clueRule.getIsAll();
                Integer matchWay = clueRule.getMatchWay();
                String ruleAttr = clueRule.getAttr();
                String finalAttr = ExplainUtil.isSubFormDuplicate(fieldAttrEntity.getFieldType()) ? attr + "." + subAttr : fieldAttrEntity.getAttr();
                //自定义字段并且命中了规则
                boolean isCustomerAttrHitRule = Objects.equals(BasicConstant.ONE, fieldAttrEntity.getIsRedundant()) && Objects.equals(ruleAttr,finalAttr);
                //是自定义字段
                if (isCustomerAttrHitRule) {
                    //全部模板
                    if (Objects.equals(isAll,BasicConstant.ONE)){
                        if(ExplainUtil.isSubFormDuplicate(fieldAttrEntity.getFieldType()) && Objects.nonNull(fieldAttrEntity.getSubForm())){
                            List<? extends FieldAttrEntity> subExplainList = fieldAttrEntity.getSubForm().getItems();
                            if (CollectionsUtil.isNotEmpty(subExplainList)){
                                List<CustomRecheckRulePojo> customRecheckRules = null;
                                for (FieldAttrEntity subAttrEntity : subExplainList) {
                                    if(Objects.equals(subAttr,subAttrEntity.getAttr())){
                                        //拿到子表单行文本配置的关联字段
                                        customRecheckRules = subAttrEntity.getCustomRecheckRules();
                                        break;
                                    }
                                }
                                //当前字段是子表单类型的单行文本配置了重复规则
                                customGlobalRecheck(finalAttr,matchWay,boolQueryBuilder, customRecheckRules,recheckAddEditDTO);
                                //命中到字段，结束
                                break;
                            }
                        }else {
                            //普通单行文本配置了重复规则
                            customGlobalRecheck(finalAttr,matchWay,boolQueryBuilder, fieldAttrEntity.getCustomRecheckRules(),recheckAddEditDTO);
                            break;
                        }
                    }else {
                        //仅模板内
                        getLinkSubForm(matchWay,finalAttr, formId, boolQueryBuilder, recheckingAddRuleHelp.getExplainMap(formId, recheckAddEditDTO.getCorpid()),recheckAddEditDTO.getSubIndexTypeEnum().getType(),recheckAddEditDTO);
                        break;
                    }
                }
            }
        }
    }

    /**
     * @description 自定义字段全局判重，包括子表单单行文本和普通单行文本
     * @author yanglei
     * @date 2022/11/17 20:30
     * @param finalAttr attr
     * @param matchWay 匹配方式
     * @param boolQueryBuilder 查重条件
     * @param customRecheckRules 自定义关联选项
     * @param recheckAddEditDTO 顶级传参
     */
    private void customGlobalRecheck(String finalAttr,Integer matchWay,BoolQueryBuilder boolQueryBuilder, List<CustomRecheckRulePojo> customRecheckRules, RecheckAddEditDTO recheckAddEditDTO) throws XbbException{
        List<Long> allFormIdList = recheckAddEditDTO.getAllFormIdList();
        if (Objects.isNull(customRecheckRules)) {
            customRecheckRules = new ArrayList<>();
        }
        //非旗舰版套餐不存在自定义字段全局判重，所以只添加当前模板，所以把关联选项清楚，筛入当前模板
        if (!Objects.equals(recheckAddEditDTO.getFeeType(), PackageTypeEnum.ULTIMATE.getType())){
            customRecheckRules.clear();
        }
        //自定义全局关联关系需要添加当前模板
        CustomRecheckRulePojo currentFormRecheck = new CustomRecheckRulePojo();
        currentFormRecheck.setAttr(finalAttr);
        currentFormRecheck.setFormId(recheckAddEditDTO.getFormId());
        customRecheckRules.add(currentFormRecheck);
        for (CustomRecheckRulePojo customRecheckRulePojo : customRecheckRules) {
            Long linkFormId = customRecheckRulePojo.getFormId();
            String linkAttr = customRecheckRulePojo.getAttr();
            //判断当前关联表单以及当前表单下的关联字段是否处于启用状态
            //有包含的说明当前关联表单处于启用状态
            if (allFormIdList.contains(linkFormId)){
                //查找关联表单的解释
                getLinkSubForm(matchWay,linkAttr, linkFormId, boolQueryBuilder, recheckingAddRuleHelp.getExplainMap(linkFormId, recheckAddEditDTO.getCorpid()),recheckAddEditDTO.getSubIndexTypeEnum().getType(),recheckAddEditDTO);
            }
        }
        //流水号特殊处理
        if (Objects.equals(finalAttr,FieldTypeEnum.SERIALNO.getAlias())){
            serialNoCheckRepeat(boolQueryBuilder,recheckAddEditDTO.getValue(),allFormIdList);
        }
    }


    /**
     * 对当前模版关联的其他模版的子表单字段做处理
     * @param linkSubAttr
     * @param linkFormId
     * @param boolQueryBuilder
     */
    public void getLinkSubForm(Integer macthWay,String linkSubAttr, Long linkFormId, BoolQueryBuilder boolQueryBuilder, Map<String, FieldAttrEntity> explainList, String subIndexType, RecheckAddEditDTO recheckAddEditDTO){
        //根据linkAttr判断关联的是否是子表单类型
        String[] split = linkSubAttr.split("\\.");
        String value = recheckAddEditDTO.getValue().toString();
        FieldAttrEntity linkData = new FieldAttrEntity();
        if (split.length > 1){
            //说明是子表单
            List<String> subAttrList = new ArrayList<>(Arrays.asList(split));
            //根据表单id查询解释，判断关联字段是否处于开启状态
            linkData = explainList.get(subAttrList.get(0));
            if (Objects.nonNull(linkData)){
                //不为空，说明当前模版的这个字段处于启用状态
                SubFormPoJo subForm = linkData.getSubForm();
                Integer fieldType = linkData.getFieldType();
                //判断内层的表单是否处于启用状态
                if (Objects.nonNull(subForm) && CollectionsUtil.isNotEmpty(subForm.getItems())){
                    List<? extends FieldAttrEntity> items = subForm.getItems();
                    items.forEach(item -> {
                        if (Objects.equals(item.getAttr(), subAttrList.get(1))){
                            //处于启用状态
                            //当前关联字段处于启用状态
                            //判断是关联的电话子表单还是普通子表单
                            boolean subPhoneFlag = Objects.equals(fieldType, FieldTypeEnum.CONTACT_NUMBER.getType());
                            boolean subCommonFlag = Objects.equals(fieldType, FieldTypeEnum.SUB_FORM.getType());
                            if (subPhoneFlag){
                                //关联的是电话子表单
                                packageMatchBoolQueryBuilder(linkSubAttr,Arrays.asList(value),boolQueryBuilder,Arrays.asList(linkFormId),macthWay);
                            }else if (subCommonFlag){
                                //关联的是普通子表单
                                RepeatSearchFieldPojo repeatSearchFieldPojo = new RepeatSearchFieldPojo();
                                repeatSearchFieldPojo.setAttr(linkSubAttr);
                                repeatSearchFieldPojo.setBusinessType(recheckAddEditDTO.getBusinessType());
                                repeatSearchFieldPojo.setFormId(linkFormId);
                                repeatSearchFieldPojo.setValue(value);
                                repeatSearchFieldPojo.setMatchWay(macthWay);
                                repeatSearchFieldPojo.setSubValueList(recheckAddEditDTO.getSubValueList());
                                HasChildQueryBuilder hasChildQueryBuilder = subFormQueryBuilder(subIndexType, recheckAddEditDTO.getCorpid(), repeatSearchFieldPojo);
                                boolQueryBuilder.should(hasChildQueryBuilder);
                            }
                        }
                    });
                }
            }
        }else {
            //不是子表单
            linkData = explainList.get(linkSubAttr);
            if (Objects.nonNull(linkData)){
                //流水号特殊处理
                if (Objects.equals(linkSubAttr,FieldTypeEnum.SERIALNO.getAlias())){
                    serialNoCheckRepeat(boolQueryBuilder,value,Arrays.asList(linkFormId));
                }else {
                    //当前关联字段处于启用状态
                    packageMatchBoolQueryBuilder(linkSubAttr,Arrays.asList(value),boolQueryBuilder,Arrays.asList(linkFormId),macthWay);
                }
            }

        }
    }

    /**
     * @description 子表单查重条件封装
     * @author yanglei
     * @date 2022/11/17 12:37
     * @param indexType
     * @param corpid
     * @param repeatSearchFieldPojo
     * @return HasChildQueryBuilder
     */
    public HasChildQueryBuilder subFormQueryBuilder(String indexType, String corpid, RepeatSearchFieldPojo repeatSearchFieldPojo){
        String[] split = repeatSearchFieldPojo.getAttr().split("\\.");
        Integer matchWay = repeatSearchFieldPojo.getMatchWay();
        List<String> subValueList = repeatSearchFieldPojo.getSubValueList();
        List<String> valueList;
        if(CollectionsUtil.isNotEmpty(subValueList)){
            valueList = subValueList;
        }else {
            valueList = Arrays.asList(repeatSearchFieldPojo.getValue());
        }
        String childAttr = split[1];
        BoolQueryBuilder childQueryBuilder = boolQuery();
        childQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        childQueryBuilder.filter(termQuery("del",0));
        childQueryBuilder.filter(termQuery("formId",repeatSearchFieldPojo.getFormId()));
        //全局判重和单模板查重仅仅一个formIdList多少的问题
        switch (Objects.requireNonNull(RecheckMatchWayEnum.getByCode(matchWay))) {
            case FUZZY_MATCH:
                childQueryBuilder.filter(matchPhraseQuery("data." + childAttr, valueList.get(0)));
                break;
            case EXACT_MATCH:
                childQueryBuilder.filter(termsQuery("data." + childAttr +".keyword", valueList));
                break;
            default:
                break;
        }
        return JoinQueryBuilders.hasChildQuery(indexType,childQueryBuilder, ScoreMode.Max);
    }

    /**
     * @description 名称字段在审批中 新建不允许重复和查重规则处理
     * @author yanglei
     * @date 2022/11/23 16:03
     * @param recheckAddEditDTO
     * @param ruleList 规则列表
     * @param isNameFlag 是否符合名称字段查重的场景
     */
    protected List<PaasProcessDataEntity> handleApprovalNameRecheckRule(RecheckAddEditDTO recheckAddEditDTO,List<RecheckFormRulePojo> ruleList,Boolean isNameFlag){
        for (RecheckFormRulePojo formRulePojo : ruleList) {
            RecheckAttrRulePojo attrRulePojo = recheckingAddRuleHelp.getRecheckAttrRuleByBusinessType(recheckAddEditDTO.getBusinessType(),formRulePojo);
            if (Objects.isNull(attrRulePojo)){
                continue;
            }
            //规则中的字段attr
            String ruleAttr = attrRulePojo.getAttr();
            //当前字段开启了新建不允许重复在规则
            if(isNameFlag && Objects.equals(recheckAddEditDTO.getAttr(),ruleAttr)){
                return executeQueryByMatchAndAll(recheckAddEditDTO, attrRulePojo.getMatchWay(), attrRulePojo.getIsAll());
            }
        }
        return new ArrayList<>();
    }

    /**
     * @description 名称字段在审批中的查询结果
     * @author yanglei
     * @date 2022/11/23 15:02
     * @param recheckAddEditDTO
     * @param matchWay 匹配方式
     * @param isAll 是否全部模板
     * @return List<PaasProcessDataEntity>
     */
    protected List<PaasProcessDataEntity> executeQueryByMatchAndAll(RecheckAddEditDTO recheckAddEditDTO,Integer matchWay,Integer isAll){
        Long formId = recheckAddEditDTO.getFormId();
        String attr = recheckAddEditDTO.getAttr();
        String value = recheckAddEditDTO.getValue().toString();
        String corpid = recheckAddEditDTO.getCorpid();
        Integer businessType = recheckAddEditDTO.getBusinessType();
        if(Objects.equals(isAll,BasicConstant.ONE)){
            if (Objects.equals(matchWay,RecheckMatchWayEnum.EXACT_MATCH.getCode())){
                //全模板精确
                return paasProcessDataModel.getInApprovalData(businessType, attr, value, corpid);
            }else {
                //全模板模糊
                return paasProcessDataModel.getInApprovalDataByLikeCondition(businessType, attr, value, corpid, null);
            }
        }else {
            if (Objects.equals(matchWay,RecheckMatchWayEnum.EXACT_MATCH.getCode())){
                //单模板精确
                return paasProcessDataModel.getInApprovalDataByFormId(businessType, attr, value, corpid, formId);
            }else {
                //单模板模糊
                return paasProcessDataModel.getInApprovalDataByLikeCondition(businessType, attr, value, corpid, formId);
            }
        }
    }

}
